﻿using System;

namespace Core
{
    /// <summary>
    /// 版本号：
    ///
    /// Major：主版本号，当API的兼容性变化时，递增，游戏一般不存在API兼容性问题，主版本号可以不变
    /// Minor：次版本号，增加功能，递增
    /// Patch：修订号，BUG修复，递增
    ///
    /// 上一级有变动时，下级要归零
    /// </summary>
    public struct Version : IEquatable<Version>, IComparable<Version>
    {
        public static readonly Version Invalid = Parse(0, 0, 0);

        public uint Major;

        /// <summary>
        /// 次版本号，增加功能，递增
        /// </summary>
        public uint Minor;

        /// <summary>
        /// 修订号，BUG修复，递增
        /// </summary>
        public uint Patch;

        ///// <summary>
        ///// 日期
        ///// </summary>
        //public string Data;

        ///// <summary>
        ///// base、alpha、beta、RC、release
        ///// </summary>
        //public string Alphabet;

        public Version(uint major, uint minor, uint patch)
        {
            Major = major;
            Minor = minor;
            Patch = patch;
        }

        public Version(string str)
        {
            var v = Parse(str);
            Major = v.Major;
            Minor = v.Minor;
            Patch = v.Patch;
        }

        public static Version Parse(uint major, uint minor, uint patch)
        {
            Version v;
            v.Major = major;
            v.Minor = minor;
            v.Patch = patch;
            return v;
        }

        public static Version Parse(string str)
        {
            string[] parts = str.Split('.');
            if (parts.Length != 3)
            {
                log.err($"Version格式非法，无法解析。{str}");
                return Invalid;
            }

            if (!uint.TryParse(parts[0], out uint major) ||
                !uint.TryParse(parts[1], out uint minor) ||
                !uint.TryParse(parts[2], out uint patch))
            {
                log.err($"Version格式非法，无法解析。{str}");
                return Invalid;
            }

            return Parse(major, minor, patch);
        }

        public int CompareTo(object obj)
        {
            if (obj == null || (obj is Version) == false)
            {
                return 1;
            }
            Version other = (Version)obj;
            return CompareTo(other);
        }

        public int CompareTo(Version other)
        {
            if (Major != other.Major)
            {
                return Major.CompareTo(Major);
            }

            if (Minor != other.Minor)
            {
                return Minor.CompareTo(other.Minor);
            }

            if (Patch != other.Patch)
            {
                return Patch.CompareTo(other.Patch);
            }

            return 0;
        }

        public static bool operator !=(Version a, Version b)
        {
            return !(a == b);
        }

        public static bool operator ==(Version a, Version b)
        {
            return a.Major == b.Major && a.Minor == b.Minor && a.Patch == b.Patch;
        }

        public static bool operator >(Version a, Version b)
        {
            if (a.Major > b.Major) return true;
            if (a.Major < b.Major) return false;
            if (a.Minor > b.Minor) return true;
            if (a.Minor < b.Minor) return false;
            if (a.Patch > b.Patch) return true;
            return false;
        }

        public static bool operator <(Version a, Version b)
        {
            if (a.Major < b.Major) return true;
            if (a.Major > b.Major) return false;
            if (a.Minor < b.Minor) return true;
            if (a.Minor > b.Minor) return false;
            if (a.Patch < b.Patch) return true;
            return false;
        }

        public static bool operator >=(Version a, Version b)
        {
            return !(a < b);
        }

        public static bool operator <=(Version a, Version b)
        {
            return !(a > b);
        }

        public readonly bool Equals(Version other) => this == other;

        public override readonly bool Equals(object obj)
        {
            if (obj == null || (obj is Version) == false)
            {
                return false;
            }
            return Equals((Version)obj);
        }

        public override readonly int GetHashCode()
        {
            return Major.GetHashCode() ^ (Minor.GetHashCode() << 2) ^ (Patch.GetHashCode() >> 2);
        }

        public override readonly string ToString()
        {
            return $"({Major}.{Minor}.{Patch})";
        }
    }
}
